home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / CD32 / CD32_Support / examples / cdgsxl / AudioCDXL.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-27  |  9.7 KB  |  409 lines

  1. /*************
  2.  
  3.     AudioCDXL.c
  4.  
  5.     W.D.L 930330
  6.  
  7. **************/
  8.  
  9. /*
  10.  * COPYRIGHT: Unless otherwise noted, all files are Copyright (c) 1993-1999
  11.  * Amiga, Inc.  All rights reserved.
  12.  *
  13.  * DISCLAIMER: This software is provided "as is".  No representations or
  14.  * warranties are made with respect to the accuracy, reliability, performance,
  15.  * currentness, or operation of this software, and all use is at your own risk.
  16.  * Neither Amiga nor the authors assume any responsibility or liability
  17.  * whatsoever with respect to your use of this software.
  18.  */
  19.  
  20.  
  21. // Tab size is 8!
  22.  
  23. #include <exec/types.h>
  24. #include <graphics/gfxbase.h>
  25.  
  26. #include <devices/audio.h>
  27. #include "devices/cd.h"
  28.  
  29. #include <hardware/custom.h>
  30. #include <hardware/dmabits.h>
  31. #include <hardware/intbits.h>
  32.  
  33. #include <clib/exec_protos.h>
  34. #include <clib/alib_protos.h>
  35.  
  36. #include <pragmas/exec_pragmas.h>
  37.  
  38. #include <string.h>    // for setmem()
  39.  
  40. #include "cdxl/cdxlob.h"
  41. #include "cdxl/runcdxl.h"
  42. #include "cdxl/debugsoff.h"
  43.  
  44. /*    // Uncomment to get debug output turned on
  45. #define KPRINTF
  46. #include "cdxl/debugson.h"
  47. */
  48.  
  49. IMPORT struct ExecBase    * SysBase;
  50. IMPORT struct Custom far custom;
  51.  
  52. STATIC UBYTE        * Name0 = "CDXLAUD0";
  53. STATIC struct Interrupt    * Aud0PriorInterrupt;
  54. STATIC struct Interrupt      AUD0Interrupt;
  55. STATIC BOOL          Aud0PriorEnable;
  56. STATIC BOOL          Aud1PriorEnable;
  57. STATIC BOOL          Aud0PriorSet;
  58. STATIC BOOL          Aud1PriorSet;
  59. STATIC BOOL          aud0_installed;
  60.  
  61.  
  62. STATIC struct MsgPort    * AudioPort[4];
  63. STATIC struct IOAudio      IOAudio[4];
  64. STATIC UBYTE          Channels[] = {1,2,4,8};
  65. STATIC BOOL          DeviceOpen[4];
  66.  
  67. STATIC UWORD    Period;        // Global Period
  68.  
  69. IMPORT    CDXLOB * CDXL_OB;    // Global CDXLOB
  70. IMPORT    LONG    XLSignal;
  71. IMPORT    struct Process * parent;
  72.  
  73.  
  74. IMPORT    struct GfxBase    * GfxBase;
  75.  
  76.  
  77. IMPORT    ULONG    Count;
  78. ULONG        SaveCount,AudioCount;
  79. WORD        padjust;
  80.  
  81. IMPORT BOOL    AudioSignalTask;
  82.  
  83. /*
  84.  * The AUD0 interrupt code. This routine gets called immediately after
  85.  * the audio DMA channel has read the location and length registers and
  86.  * stored their values in the back up registers. The philospy here is to
  87.  * rewrite the location registers to point to the other audio buffer in
  88.  * preparation for the next time the audio DMA reads them. It seems that
  89.  * the audio period that was specified is sometimes off by less than 1.
  90.  * For long CDXL files, this will result in the audio getting out of
  91.  * sync with the video. What I do here is add or subtract one from the
  92.  * period to compensate for this. A better way to do this could probably
  93.  * be figured out.
  94.  */
  95. VOID __interrupt __saveds
  96. AUD0Handler( VOID )
  97. {
  98.     // clear AUD0 interrupt
  99.     custom.intreq = INTF_AUD0;
  100.  
  101.     ++AudioCount;
  102.  
  103.     if( !(CDXL_OB->flags & CDXL_DOSXL) ) {
  104.  
  105.     padjust = AudioCount - Count;
  106.     custom.aud[ 0 ].ac_per = custom.aud[ 1 ].ac_per = Period + padjust;
  107.  
  108.     if ( (SaveCount == Count) ) {
  109.         CDXL_OB->curAudio ^= 1;
  110.         AudioCount--;
  111.     } else if ( (Count - SaveCount) > 1) {
  112.         AudioCount++;
  113.         CDXL_OB->curAudio = CDXL_OB->curVideo;
  114.     } else {
  115.         CDXL_OB->curAudio = CDXL_OB->curVideo;
  116.     }
  117.  
  118.     D(PRINTF("%ld-%ld ",CDXL_OB->curAudio,padjust);)
  119.  
  120.     // Point the location registers to the buffer that is currently being filled
  121.     // by the CDXL. If we are timed right, when the CDXL is done reading, the
  122.     // audio DMA should be ready to reread these location registers.
  123.     custom.aud[ 0 ].ac_ptr = custom.aud[ 1 ].ac_ptr = (USHORT *)CDXL_OB->audio[CDXL_OB->curAudio];
  124.  
  125.     if ( AudioSignalTask )
  126.         Signal( (struct Task *)parent, XLSignal );
  127.  
  128.     } else {
  129.     // Point the location registers to the buffer that is currently being filled
  130.     // by the CDXL. If we are timed right, when the CDXL is done reading, the
  131.     // audio DMA should be ready to reread these location registers.
  132.     padjust = (AudioCount - Count);
  133.     custom.aud[ 0 ].ac_per = custom.aud[ 1 ].ac_per = Period + padjust;
  134.     custom.aud[ 0 ].ac_ptr = custom.aud[ 1 ].ac_ptr = (USHORT *)CDXL_OB->audio[CDXL_OB->curAudio];
  135.  
  136.  
  137.     if ( (SaveCount == Count) ) {
  138.         CDXL_OB->curAudio ^= 1;
  139.         AudioCount--;
  140.     } else if ( (Count - SaveCount) > 1) {
  141.         AudioCount++;
  142.         CDXL_OB->curAudio = CDXL_OB->curVideo;
  143.     } else {
  144.         CDXL_OB->curAudio = CDXL_OB->curVideo;
  145.     }
  146.  
  147. //    custom.aud[ 0 ].ac_ptr = custom.aud[ 1 ].ac_ptr = (USHORT *)CDXL_OB->audio[CDXL_OB->curAudio];
  148.  
  149.     Signal( (struct Task *)parent, XLSignal );
  150.     }
  151.  
  152.     SaveCount = Count;
  153.  
  154. } // AUD0Handler()
  155.  
  156.  
  157. /*
  158.  * Free the audio channels.
  159.  */
  160. STATIC VOID
  161. FreeAudio( VOID )
  162. {
  163.     int i;
  164.  
  165.     for ( i = 0; i < 4; i++ ) {
  166.     if ( DeviceOpen[i] ) {
  167.         CloseDevice( (struct IORequest *)&IOAudio[i] );
  168.         DeviceOpen[i] = NULL;
  169.         D(PRINTF("Closing channel %ld\n",i);)
  170.     } else {
  171.         D(PRINTF("NOT Closing channel %ld\n",i);)
  172.     }
  173.  
  174.     if ( AudioPort[i] ) {
  175.         DeleteMsgPort( AudioPort[i] );
  176.         AudioPort[i] = NULL;
  177.         D(PRINTF("Deleting Port %ld\n",i);)
  178.     } else {
  179.         D(PRINTF("NOT Deleting Port %ld\n",i);)
  180.     }
  181.     }
  182.  
  183. } // FreeAudio()
  184.  
  185.  
  186. /*
  187.  * Allocate the audio channels. Probably don't need to allocate all 4 but...
  188.  */
  189. STATIC
  190. AllocAudio( VOID )
  191. {
  192.     int    i,ret = RC_OK;
  193.  
  194.     for ( i = 0; i < 4; i++ ) {
  195.     setmem( &IOAudio[i], sizeof ( struct IOAudio ), 0 );
  196.  
  197.     if ( AudioPort[i] = CreateMsgPort() ) {
  198.         IOAudio[i].ioa_Request.io_Message.mn_ReplyPort = AudioPort[i];
  199.         IOAudio[i].ioa_Request.io_Message.mn_Node.ln_Pri = 127;
  200.         IOAudio[i].ioa_AllocKey = 0;
  201.         IOAudio[i].ioa_Data = &Channels[i];
  202.         IOAudio[i].ioa_Length = 1;
  203.         if ( !OpenDevice("audio.device",0,(struct IORequest *)&IOAudio[i],0) ) {
  204.         DeviceOpen[i] = TRUE;
  205.         D(PRINTF("Got channel %ld\n",i);)
  206.         } else {
  207.         DeviceOpen[i] = FALSE;
  208.         D(PRINTF("Did NOT get channel %ld\n",i);)
  209.         ret = RC_NO_AUDIODEVICE;
  210.         break;
  211.         }
  212.     } else {
  213.         ret = RC_NO_MEM;
  214.         break;
  215.     }
  216.     }
  217.  
  218.     if ( ret )
  219.     FreeAudio();
  220.  
  221.     return( ret );
  222.  
  223. } // AllocAudio()
  224.  
  225.  
  226. /*
  227.  * Disable AUD0 & AUD1 DMA as well as the AUD0 interrupt.
  228.  */
  229. VOID
  230. StopAudio( VOID )
  231. {
  232.     // disable AUD0 DMA
  233.     custom.dmacon = DMAF_AUD0;
  234.  
  235.     // disable AUD1 DMA
  236.     custom.dmacon = DMAF_AUD1;
  237.  
  238.     // disable AUD0 interrupt
  239.     custom.intena = INTF_AUD0;
  240.  
  241.     // clear AUD0 interrupt
  242.     custom.intreq = INTF_AUD0;
  243.  
  244. } // StopAudio()
  245.  
  246.  
  247. /*
  248.  * Enable AUD0 & AUD1 DMA as well as the AUD0 interrupt.
  249.  */
  250. VOID
  251. StartAudio( VOID )
  252. {
  253.     // clear AUD0 interrupt
  254.     custom.intreq = INTF_AUD0;
  255.  
  256.     // enable AUD0 DMA
  257.     custom.dmacon = DMAF_SETCLR|DMAF_MASTER|DMAF_AUD0;
  258.  
  259.     // enable AUD1 DMA
  260.     custom.dmacon = DMAF_SETCLR|DMAF_MASTER|DMAF_AUD1;
  261.  
  262.     // enable AUD0 interrupt
  263.     custom.intena = INTF_SETCLR|INTF_AUD0;
  264.  
  265.     AudioCount = 0;
  266.  
  267. } // StartAudio()
  268.  
  269.  
  270. /*
  271.  * Restore the audio system back to how we found it.
  272.  */
  273. VOID
  274. QuitAudio( VOID )
  275. {
  276.     if ( aud0_installed ) {
  277.     aud0_installed = FALSE;
  278.  
  279.     StopAudio();
  280.  
  281.     /*
  282.      * Remove the interrupt we installed and replace it
  283.      * with the old one (if there was one).
  284.      */
  285.     SetIntVector(INTB_AUD0, Aud0PriorInterrupt);
  286.  
  287.     if(Aud0PriorEnable) {
  288.         custom.intena = INTF_SETCLR|INTF_AUD0;
  289.         Aud0PriorEnable = FALSE;
  290.     }
  291.  
  292.     if(Aud1PriorEnable) {
  293.         custom.intena = INTF_SETCLR|INTF_AUD1;
  294.         Aud1PriorEnable = FALSE;
  295.     }
  296.  
  297.     if ( Aud0PriorSet ) {
  298.         custom.intreq = INTF_AUD0;
  299.         Aud0PriorSet = FALSE;
  300.     }
  301.  
  302.     if ( Aud1PriorSet ) {
  303.         custom.intreq = INTF_AUD1;
  304.         Aud1PriorSet = FALSE;
  305.     }
  306.     }
  307.  
  308.     // Free the audio channels we allocated.
  309.     FreeAudio();
  310.  
  311. } // QuitAudio()
  312.  
  313.  
  314. /*
  315.  * Install an AUD0 interrupt
  316.  */
  317. AddAudioInterrupt( VOID )
  318. {
  319.     setmem( &AUD0Interrupt, sizeof ( AUD0Interrupt ), 0 );
  320.  
  321.     /* Initialize the Interrupt node */
  322.     AUD0Interrupt.is_Node.ln_Type = NT_INTERRUPT;
  323.     AUD0Interrupt.is_Node.ln_Pri  = 0;
  324.     AUD0Interrupt.is_Node.ln_Name = Name0;
  325.  
  326.     AUD0Interrupt.is_Data = (APTR)NULL;
  327.     AUD0Interrupt.is_Code = AUD0Handler;
  328.  
  329.     custom.intena = INTF_AUD0|INTF_AUD1;
  330.     custom.intreq = INTF_AUD0|INTF_AUD1;
  331.  
  332.     // Install the new interrupt handler
  333.     Aud0PriorInterrupt = SetIntVector( INTB_AUD0, &AUD0Interrupt );
  334.  
  335.     if (Aud0PriorInterrupt) {
  336.     D(PRINTF("Replaced the %ls AUD0 interrupt handler\n",
  337.         Aud0PriorInterrupt->is_Node.ln_Name);)
  338.     }
  339.  
  340.     return( (int)(aud0_installed = TRUE) );
  341.  
  342. } // AddAudioInterrupt()
  343.  
  344.  
  345. /*
  346.  * Set up the audio system.
  347.  */
  348. InitAudio( CDXLOB * CDXL_ob )
  349. {
  350.     ULONG    freq;
  351.     LONG    rate;
  352.     UWORD    period;
  353.     int        ret;
  354.  
  355.     // If this CDXL has no audio, there is no need.
  356.     if ( !CDXL_ob->AudioSize )
  357.     return( RC_OK );
  358.  
  359.     if ( ret = AllocAudio() )
  360.     return( ret );
  361.  
  362.     // Save state of AUD0 & AUD1 interrupts
  363.     Aud0PriorEnable = custom.intenar & INTF_AUD0 ? TRUE : FALSE;
  364.     Aud1PriorEnable = custom.intenar & INTF_AUD1 ? TRUE : FALSE;
  365.     Aud0PriorSet = custom.intreqr & INTF_AUD0 ? TRUE : FALSE;
  366.     Aud1PriorSet = custom.intreqr & INTF_AUD1 ? TRUE : FALSE;
  367.  
  368.     // Add the Audio interrupt
  369.     AddAudioInterrupt();
  370.  
  371.     // Calculate period
  372.     freq = ( SYSTEM_PAL ? PAL_FREQ : NTSC_FREQ );
  373.  
  374.     D(
  375.      if ( SYSTEM_PAL ) {
  376.     D(PRINTF("SYSTEM_PAL... \n");)
  377.      } else {
  378.     D(PRINTF("SYSTEM_NTSC... \n");)
  379.      }
  380.     )
  381.  
  382.     D(PRINTF("InitAudio() 4.1 freq= %ld, CDXL_ob->AudioSize= %ld, CDXL_ob->FrameSize= %ld\n",
  383.     freq,CDXL_ob->AudioSize,CDXL_ob->FrameSize);)
  384.  
  385.     if ( CDXL_ob->flags & CDXL_DOSXL) {
  386.     rate = INTDIV( (( CDXL_ob->ReadXLSpeed * DEFAULT_SECTOR_SIZE) * CDXL_ob->AudioSize ), CDXL_ob->FrameSize );
  387.     } else {
  388.     rate = INTDIV( ( DATA_TRANS_RATE * CDXL_ob->AudioSize ), CDXL_ob->FrameSize );
  389.     }
  390.  
  391.     period = (UWORD) INTDIV( freq, rate );
  392.  
  393.     D(PRINTF("InitAudio() 4.2 rate= %ld, period= %ld\n",rate,period);)
  394.  
  395.     Period = period;    // Set Global pointer
  396.     padjust = 0;    // Global period adjuster.
  397.  
  398.     CDXL_ob->curAudio = 0;
  399.  
  400.     // Set up the volume,period and length
  401.     custom.aud[ 0 ].ac_vol = custom.aud[ 1 ].ac_vol = CDXL_ob->Volume;
  402.     custom.aud[ 0 ].ac_per = custom.aud[ 1 ].ac_per = period;
  403.     custom.aud[ 0 ].ac_ptr = custom.aud[ 1 ].ac_ptr = (USHORT *)CDXL_ob->audio[CDXL_ob->curAudio];
  404.     custom.aud[ 0 ].ac_len = custom.aud[ 1 ].ac_len = ( CDXL_ob->AudioSize / sizeof( UWORD) );
  405.  
  406.     return( RC_OK );
  407.  
  408. } // InitAudio()
  409.